
#ifndef __FRAGMENT_BASE_H__
#define __FRAGMENT_BASE_H__




// Optimized phong, use if mirrowed reflection vector pre-computed
//half Phong(half3 R, half3 L, half Exp)
//{	
//	half fNormFactor = Exp * ONE_OVER_TWO_PI + ONE_OVER_TWO_PI;		// 1 ALU
//	return fNormFactor *  pow(saturate(dot(L, R)), Exp);					// 4 ALU
//	// 5 ALU
//}
//
//half Phong(half3 N, half3 V, half3 L, half Exp)
//{
//	half3 R = reflect(-V, N);	// 3 ALU
//	return Phong(R, L, Exp);	// 5 ALU
//	// 8 ALU
//}

//////////////////////////////// Blinn BRDF model /////////////////////////////////////
// - Blinn model has good properties for plastic and some metallic surfaces. 
// - Good for general use. Very cheap.
// *NOTE* We should also multiply by the clamped N.L factor. However this is 
// delegated to the shader part for performance reasons

half BlinnBRDF(half3 N, half3 V, half3 L, half Gloss)
{
	half3 H = normalize(V + L);

	// Compute perceptually linear exponent in range 2-2048
	float power = exp2( 10.h * Gloss + 1.h );

	float fNormFactor = power * (1.0/8.0) + (2.0/8.0);
	return fNormFactor * pow( saturate( dot( N, H ) ), power );
}




/*
float3 GetDynamicLighting(float3 WorldPosition, float3 WorldNormal, float3 CameraVector, float2 InUV, float3 DiffuseColor, float4 SpecularAndPower, float4 LightAttenuation)
{
	float3 OutLighting = 0;

	//float3 WorldLightVector = LightDirectionAndChannel.xyz;
	float DistanceAttenuation = 1;
#if RADIAL_ATTENUATION
	WorldLightVector = (LightPositionAndInvRadius.xyz - WorldPosition) * LightPositionAndInvRadius.w;
	DistanceAttenuation = RadialAttenuation(WorldLightVector, LightColorAndFalloffExponent.w);
#endif

	float SpotFalloff = 1;
#if SPOT_ATTENUATION
	SpotFalloff = SpotAttenuation(WorldLightVector.xyz, -LightDirectionAndChannel.xyz, SpotAngles);
#endif

#if RADIAL_ATTENUATION || SPOT_ATTENUATION
	BRANCH
		if (DistanceAttenuation > 0 && SpotFalloff > 0)
#endif
		{
			//float3 WorldLightVectorNormalized = normalize(WorldLightVector);
			float3 ReflectionVector = reflect(CameraVector, WorldNormal);

			float3 IncidentLighting = PointLightPhong(
				DiffuseColor, 
				1,   
				float3(0,0,0), 
				DecodeSpecularColor(SpecularAndPower),
				DecodeSpecularPower(SpecularAndPower), 
				WorldLightVectorNormalized, 
				CameraVector, 
				WorldNormal,
				ReflectionVector);

			float DistanceFade = 0;
#if !(RADIAL_ATTENUATION || SPOT_ATTENUATION)
			DistanceFade = DistanceFromCameraFade(WorldPosition, CameraPositionPS.xyz);
#endif
			// Combine the whole scene dominant light shadow with per-object shadows and the light function if one was rendered
			float3 DynamicShadowing = lerp(1, LightAttenuation.a, DistanceFade) * LightAttenuation.rgb;

			float3 CombinedAttenuation = DistanceAttenuation * SpotFalloff * DynamicShadowing * LightColorAndFalloffExponent.rgb;
			OutLighting = IncidentLighting * CombinedAttenuation;
		}
		return OutLighting;
}

*/


#ifdef OPENGL

/*
 */
#include <VCommon.h>

/*
 */
#ifdef USE_ARB_SAMPLE_SHADING
	##extension GL_ARB_sample_shading : enable
#endif

/* fragment in
 */
in float4 s_texcoord_0;
in float4 s_texcoord_1;
in float4 s_texcoord_2;
in float4 s_texcoord_3;
in float4 s_texcoord_4;
in float4 s_texcoord_5;
in float4 s_texcoord_6;
in float4 s_texcoord_7;
in float4 s_texcoord_8;
in float4 s_texcoord_9;
in float4 s_texcoord_10;

/* fragment out
 */
out half4 s_frag_color;
out half4 s_frag_data_0;
out half4 s_frag_data_1;
out half4 s_frag_data_2;
out half4 s_frag_data_3;
out half4 s_frag_color_0;
out half4 s_frag_color_1;

/* vertex transformation
 */
float4 getPosition(float4 vertex) {
	return mul4(s_projection,vertex);
}

/* deferred texture sampling
 */
half4 texture2DDeferredRect(SAMPLER_2DMS s_texture,float2 texcoord,float2 texsize) {
	#ifdef MULTISAMPLE_0
		half4 deferred = texture(s_texture,texcoord * Viewport.zw);
	#else
		half4 deferred = texelFetch(s_texture,int2(texcoord * texsize * Viewport.zw),0);
	#endif
	return deferred;
}

half4 texture2DDeferredNorm(SAMPLER_2DMS s_texture,float2 texcoord) {
	#ifdef MULTISAMPLE_0
		half4 deferred = texture(s_texture,texcoord);
	#else
		half4 deferred = texelFetch(s_texture,int2(texcoord * Viewport.xy),0);
	#endif
	return deferred;
}

half4 texture2DDeferredNorm2(SAMPLER_2DMS s_texture,float2 texcoord) {
	#ifdef MULTISAMPLE_0
		half4 deferred = texture(s_texture,texcoord);
	#else
		half4 deferred = texelFetch(s_texture,int2(texcoord * Viewport.xy * 2.0f - 0.0001f),0);
	#endif
	return deferred;
}

/* alpha test texture sampling
 */
half4 texture2DAlpha(sampler2D s_texture,float2 texcoord,half scale) {
	half4 value = texture(s_texture,texcoord);
	#ifdef ALPHA_TEST
		value.w = value.w * scale;
		#ifdef MULTISAMPLE_0
			if(value.w <= 0.5f) discard;
		#elif USE_ARB_SAMPLE_SHADING
			#ifdef QUALITY_HIGH
				gl_SampleMask[0] = 0x00;
				half2 dx = dFdx(texcoord);
				half2 dy = dFdy(texcoord);
				#define SAMPLE(X,Y,MASK) if(texture(s_texture,texcoord + dx * (X) + dy * (Y)).w * scale > 0.5f) gl_SampleMask[0] |= MASK;
				#ifdef MULTISAMPLE_2
					SAMPLE( 0.25f, 0.25f,0x01)
					SAMPLE(-0.25f,-0.25f,0x02)
				#elif MULTISAMPLE_4
					SAMPLE(-0.125f,-0.375f,0x01)
					SAMPLE( 0.375f,-0.125f,0x02)
					SAMPLE(-0.375f, 0.125f,0x04)
					SAMPLE( 0.125f, 0.375f,0x08)
				#elif MULTISAMPLE_8
					SAMPLE(-0.125f,-0.375f,0x03)
					SAMPLE( 0.375f,-0.125f,0x0c)
					SAMPLE(-0.375f, 0.125f,0x30)
					SAMPLE( 0.125f, 0.375f,0xc0)
				#elif MULTISAMPLE_16
					SAMPLE(-0.125f,-0.375f,0x000f)
					SAMPLE( 0.375f,-0.125f,0x00f0)
					SAMPLE(-0.375f, 0.125f,0x0f00)
					SAMPLE( 0.125f, 0.375f,0xf000)
				#endif
				#undef SAMPLE
			#else
				#ifdef MULTISAMPLE_2
					if(value.w < 0.49f) gl_SampleMask[0] = 0x00;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x01;
					else gl_SampleMask[0] = 0x03;
				#elif MULTISAMPLE_4
					if(value.w < 0.48f) gl_SampleMask[0] = 0x00;
					else if(value.w < 0.49f) gl_SampleMask[0] = 0x01;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x06;
					else if(value.w < 0.51f) gl_SampleMask[0] = 0x0e;
					else gl_SampleMask[0] = 0x0f;
				#elif MULTISAMPLE_8
					if(value.w < 0.48f) gl_SampleMask[0] = 0x00;
					else if(value.w < 0.49f) gl_SampleMask[0] = 0x11;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x66;
					else if(value.w < 0.51f) gl_SampleMask[0] = 0xee;
					else gl_SampleMask[0] = 0xff;
				#elif MULTISAMPLE_16
					if(value.w < 0.48f) gl_SampleMask[0] = 0x0000;
					else if(value.w < 0.49f) gl_SampleMask[0] = 0x1111;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x6666;
					else if(value.w < 0.51f) gl_SampleMask[0] = 0xeeee;
					else gl_SampleMask[0] = 0xffff;
				#endif
			#endif
		#else
			value.w = value.w * 4.0f - 1.5f;
			if(value.w <= 0.2f) discard;
		#endif
	#endif
	return value;
}

half4 texture2DAlphaDiscard(sampler2D s_texture,float2 texcoord,half scale) {
	half4 value = texture(s_texture,texcoord);
	#ifdef ALPHA_TEST
		value.w = value.w * scale;
		#ifdef MULTISAMPLE_0
			if(value.w <= 0.5f) discard;
		#elif USE_ARB_SAMPLE_SHADING
			#ifdef QUALITY_HIGH
				gl_SampleMask[0] = 0x00;
				half2 dx = dFdx(texcoord);
				half2 dy = dFdy(texcoord);
				#define SAMPLE(X,Y,MASK) if(texture(s_texture,texcoord + dx * (X) + dy * (Y)).w * scale > 0.5f) gl_SampleMask[0] |= MASK;
				#ifdef MULTISAMPLE_2
					SAMPLE( 0.25f, 0.25f,0x01)
					SAMPLE(-0.25f,-0.25f,0x02)
				#elif MULTISAMPLE_4
					SAMPLE(-0.125f,-0.375f,0x01)
					SAMPLE( 0.375f,-0.125f,0x02)
					SAMPLE(-0.375f, 0.125f,0x04)
					SAMPLE( 0.125f, 0.375f,0x08)
				#elif MULTISAMPLE_8
					SAMPLE(-0.125f,-0.375f,0x03)
					SAMPLE( 0.375f,-0.125f,0x0c)
					SAMPLE(-0.375f, 0.125f,0x30)
					SAMPLE( 0.125f, 0.375f,0xc0)
				#elif MULTISAMPLE_16
					SAMPLE(-0.125f,-0.375f,0x000f)
					SAMPLE( 0.375f,-0.125f,0x00f0)
					SAMPLE(-0.375f, 0.125f,0x0f00)
					SAMPLE( 0.125f, 0.375f,0xf000)
				#endif
				#undef SAMPLE
			#else
				#ifdef MULTISAMPLE_2
					if(value.w < 0.49f) gl_SampleMask[0] = 0x00;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x01;
					else gl_SampleMask[0] = 0x03;
				#elif MULTISAMPLE_4
					if(value.w < 0.48f) gl_SampleMask[0] = 0x00;
					else if(value.w < 0.49f) gl_SampleMask[0] = 0x01;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x06;
					else if(value.w < 0.51f) gl_SampleMask[0] = 0x0e;
					else gl_SampleMask[0] = 0x0f;
				#elif MULTISAMPLE_8
					if(value.w < 0.48f) gl_SampleMask[0] = 0x00;
					else if(value.w < 0.49f) gl_SampleMask[0] = 0x11;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x66;
					else if(value.w < 0.51f) gl_SampleMask[0] = 0xee;
					else gl_SampleMask[0] = 0xff;
				#elif MULTISAMPLE_16
					if(value.w < 0.48f) gl_SampleMask[0] = 0x0000;
					else if(value.w < 0.49f) gl_SampleMask[0] = 0x1111;
					else if(value.w < 0.50f) gl_SampleMask[0] = 0x6666;
					else if(value.w < 0.51f) gl_SampleMask[0] = 0xeeee;
					else gl_SampleMask[0] = 0xffff;
				#endif
			#endif
		#else
			if(value.w <= 0.5f) discard;
		#endif
	#endif
	return value;
}

/* alpha fade texture sampling
 */
void texture2DAlphaFadeDiscard(sampler2D s_texture,half threshold) {
	#ifdef USE_ALPHA_FADE && ALPHA_FADE
		half4 value = texture(s_texture,gl_FragCoord.xy * (1.0f / 64.0f));
		if(threshold >= 0.0f) {
			if(value.x >= threshold) discard;
		} else {
			if(value.x < 1.0f + threshold) discard;
		}
	#endif
}

/* normal texture sampling
 */
half3 texture2DNormal(sampler2D s_texture,float2 texcoord) {
	half3 value = texture(s_texture,texcoord).xyz;
	value.z = sqrt(saturate(1.0f - dot(value.xy,value.xy)));
	return value;
}

/* lightmap texture sampling
 */
half3 texture2DLightMap(sampler2D s_texture,float2 texcoord,half3 normal) {
	#ifdef USE_DIRECTIONAL_LIGHTMAPS
		texcoord *= 0.5f;
		#ifdef QUALITY_MEDIUM
			half4 weight;
			weight.x = normal.z;
			weight.y = saturate(dot(half3(0.816496f,0.0f,0.577350f),normal));
			weight.z = saturate(dot(half3(-0.408248f, 0.707106f,0.577350f),normal));
			weight.w = saturate(dot(half3(-0.408248f,-0.707106f,0.577350f),normal));
			weight = weight * weight;
			weight = weight * weight;
			half3 value_0 = texture(s_texture,texcoord).xyz * weight.x;
			half3 value_1 = texture(s_texture,texcoord + half2(0.5f,0.0f)).xyz * weight.y;
			half3 value_2 = texture(s_texture,texcoord + half2(0.0f,0.5f)).xyz * weight.z;
			half3 value_3 = texture(s_texture,texcoord + half2(0.5f,0.5f)).xyz * weight.w;
			return (value_0 + value_1 + value_2 + value_3) / dot(weight,half4(1.0f));
		#else
			return texture(s_texture,texcoord).xyz;
		#endif
	#else
		return texture(s_texture,texcoord).xyz;
	#endif
}

/* cubic texture sampling
 */
half3 texture_2d_cubic_filter(float x) {
	half x1 = fract(x);
	half x2 = x1 * x1;
	half x3 = x2 * x1;
	half x13 = x1 * 3.0f;
	half x23 = x2 * 3.0f;
	half x33 = x3 * 3.0f;
	half w0 = -x3 + x23 - x13 + 1.0f;
	half w1 = x33 - x23 * 2.0f + 4.0f;
	half w2 = -x33 + x23 + x13 + 1.0f;
	return half3(1.0f + x3 / (w2 + x3) - x1,1.0f - w1 / (w0 + w1) + x1,(w2 + x3) * (1.0f / 6.0f));
}

half4 texture2DCubic(sampler2D s_texture,float2 texcoord,float4 texsize) {
	#ifdef QUALITY_HIGH
		float2 texcoord_hg = texcoord * texsize.xy - 0.5f;
		half3 hg_x = texture_2d_cubic_filter(texcoord_hg.x);
		half3 hg_y = texture_2d_cubic_filter(texcoord_hg.y);
		float4 texcoords = texcoord.xyxy + half4(-hg_x.y,-hg_y.y,hg_x.x,hg_y.x) * texsize.zwzw;
		half4 value_00 = texture(s_texture,texcoords.xy);
		half4 value_10 = texture(s_texture,texcoords.xw);
		half4 value_01 = texture(s_texture,texcoords.zy);
		half4 value_11 = texture(s_texture,texcoords.zw);
		return lerp(lerp(value_00,value_10,hg_y.z),lerp(value_01,value_11,hg_y.z),hg_x.z);
	#else
		return texture(s_texture,texcoord);
	#endif
}

/*
 */
#include <deferred_base.h>
#ifdef AMBIENT || PROB || SPOT || OMNI || PROJ || WORLD
	#include <fragment_base_shading.h>
#endif
#ifdef OMNI
	#include <fragment_base_shadow_omni.h>
#elif PROJ
	#include <fragment_base_shadow_proj.h>
#elif AMBIENT_LIGHT || WORLD
	#include <fragment_base_shadow_world.h>
#endif

/******************************************************************************\
*
* Direct3D11
*
\******************************************************************************/

#elif DIRECT3D11

/*
 */
#include <VCommon.h>

/* texture samplers
 */
SamplerState s_sampler_0 : register(s0);
SamplerState s_sampler_1 : register(s1);
SamplerState s_sampler_2 : register(s2);
SamplerState s_sampler_3 : register(s3);
SamplerState s_sampler_4 : register(s4);
SamplerState s_sampler_5 : register(s5);
SamplerState s_sampler_6 : register(s6);
SamplerState s_sampler_7 : register(s7);
SamplerState s_sampler_8 : register(s8);
SamplerState s_sampler_9 : register(s9);
SamplerState s_sampler_10 : register(s10);
SamplerState s_sampler_11 : register(s11);
SamplerState s_sampler_12 : register(s12);
SamplerState s_sampler_13 : register(s13);
SamplerState s_sampler_14 : register(s14);
SamplerState s_sampler_15 : register(s15);

SamplerComparisonState s_sampler_compare_0 : register(s0);
SamplerComparisonState s_sampler_compare_1 : register(s1);
SamplerComparisonState s_sampler_compare_2 : register(s2);
SamplerComparisonState s_sampler_compare_3 : register(s3);
SamplerComparisonState s_sampler_compare_4 : register(s4);
SamplerComparisonState s_sampler_compare_5 : register(s5);
SamplerComparisonState s_sampler_compare_6 : register(s6);
SamplerComparisonState s_sampler_compare_7 : register(s7);
SamplerComparisonState s_sampler_compare_8 : register(s8);
SamplerComparisonState s_sampler_compare_9 : register(s9);
SamplerComparisonState s_sampler_compare_10 : register(s10);
SamplerComparisonState s_sampler_compare_11 : register(s11);
SamplerComparisonState s_sampler_compare_12 : register(s12);
SamplerComparisonState s_sampler_compare_13 : register(s13);
SamplerComparisonState s_sampler_compare_14 : register(s14);
SamplerComparisonState s_sampler_compare_15 : register(s15);

/* vertex transformation
 */
float4 getPosition(float4 vertex) {
	return mul4(s_projection,vertex);
}

/* deferred texture sampling
 */
half4 texture2DDeferredRect(TEXTURE_2DMS s_texture,SamplerState s_sampler,float2 position,float2 texsize) {
	#ifdef MULTISAMPLE_0
		half4 deferred = s_texture.SampleLevel(s_sampler,position * Viewport.zw,0.0f);
	#else
		half4 deferred = s_texture.Load(int2(position * texsize * Viewport.zw),0);
	#endif
	return deferred;
}

half4 texture2DDeferredNorm(TEXTURE_2DMS s_texture,SamplerState s_sampler,float2 texcoord) {
	#ifdef MULTISAMPLE_0
		half4 deferred = s_texture.SampleLevel(s_sampler,texcoord,0.0f);
	#else
		half4 deferred = s_texture.Load(int2(texcoord * Viewport.xy),0);
	#endif
	return deferred;
}

half4 texture2DDeferredNorm2(TEXTURE_2DMS s_texture,SamplerState s_sampler,float2 texcoord) {
	#ifdef MULTISAMPLE_0
		half4 deferred = s_texture.SampleLevel(s_sampler,texcoord,0.0f);
	#else
		half4 deferred = s_texture.Load(int2(texcoord * Viewport.xy * 2.0f - 0.0001f),0);
	#endif
	return deferred;
}

/* fragment deferred out
 */
struct FRAGMENT_DEFERRED_OUT {
	float4 color_0 : SV_TARGET0;
	#ifdef HAS_DEFERRED_COLOR
		float4 color_1 : SV_TARGET1;
	#endif
	#ifdef HAS_DEFERRED_NORMAL
		float4 color_2 : SV_TARGET2;
	#endif
	#ifdef USE_PARALLAX
		float4 color_3 : SV_TARGET3;
	#endif
	#ifdef ALPHA_TEST && !MULTISAMPLE_0 && USE_ALPHA_TEST_LEVEL_10_1
		uint coverage : SV_COVERAGE;
	#endif
};

/* fragment alpha out
 */
struct FRAGMENT_ALPHA_OUT {
	float4 color : SV_TARGET;
	#ifdef ALPHA_TEST && !MULTISAMPLE_0 && USE_ALPHA_TEST_LEVEL_10_1
		uint coverage : SV_COVERAGE;
	#endif
};

/* alpha test texture sampling
 */
FRAGMENT_ALPHA_OUT texture2DAlpha(Texture2D s_texture,SamplerState s_sampler,float2 texcoord,half scale) {
	FRAGMENT_ALPHA_OUT OUT;
	OUT.color = s_texture.Sample(s_sampler,texcoord);
	#ifdef ALPHA_TEST
		OUT.color.w = OUT.color.w * scale;
		#ifdef MULTISAMPLE_0
			if(OUT.color.w <= 0.5f) discard;
		#elif USE_ALPHA_TEST_LEVEL_10_1
			#ifdef QUALITY_HIGH
				OUT.coverage = 0x00;
				half2 dx = ddx(texcoord);
				half2 dy = ddy(texcoord);
				#define SAMPLE(X,Y,MASK) if(s_texture.Sample(s_sampler,texcoord + dx * (X) + dy * (Y)).w * scale > 0.5f) OUT.coverage |= MASK;
				#ifdef MULTISAMPLE_2
					SAMPLE( 0.25f, 0.25f,0x01)
					SAMPLE(-0.25f,-0.25f,0x02)
				#elif MULTISAMPLE_4
					SAMPLE(-0.125f,-0.375f,0x01)
					SAMPLE( 0.375f,-0.125f,0x02)
					SAMPLE(-0.375f, 0.125f,0x04)
					SAMPLE( 0.125f, 0.375f,0x08)
				#elif MULTISAMPLE_8
					SAMPLE(-0.125f,-0.375f,0x03)
					SAMPLE( 0.375f,-0.125f,0x0c)
					SAMPLE(-0.375f, 0.125f,0x30)
					SAMPLE( 0.125f, 0.375f,0xc0)
				#elif MULTISAMPLE_16
					SAMPLE(-0.125f,-0.375f,0x000f)
					SAMPLE( 0.375f,-0.125f,0x00f0)
					SAMPLE(-0.375f, 0.125f,0x0f00)
					SAMPLE( 0.125f, 0.375f,0xf000)
				#endif
				#undef SAMPLE
			#else
				#ifdef MULTISAMPLE_2
					if(OUT.color.w < 0.49f) OUT.coverage = 0x00;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x01;
					else OUT.coverage = 0x03;
				#elif MULTISAMPLE_4
					if(OUT.color.w < 0.48f) OUT.coverage = 0x00;
					else if(OUT.color.w < 0.49f) OUT.coverage = 0x01;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x06;
					else if(OUT.color.w < 0.51f) OUT.coverage = 0x0e;
					else OUT.coverage = 0x0f;
				#elif MULTISAMPLE_8
					if(OUT.color.w < 0.48f) OUT.coverage = 0x00;
					else if(OUT.color.w < 0.49f) OUT.coverage = 0x11;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x66;
					else if(OUT.color.w < 0.51f) OUT.coverage = 0xee;
					else OUT.coverage = 0xff;
				#elif MULTISAMPLE_16
					if(OUT.color.w < 0.48f) OUT.coverage = 0x0000;
					else if(OUT.color.w < 0.49f) OUT.coverage = 0x1111;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x6666;
					else if(OUT.color.w < 0.51f) OUT.coverage = 0xeeee;
					else OUT.coverage = 0xffff;
				#endif
			#endif
		#else
			OUT.color.w = OUT.color.w * 4.0f - 1.5f;
			if(OUT.color.w <= 0.2f) discard;
		#endif
	#endif
	return OUT;
}

FRAGMENT_ALPHA_OUT texture2DAlphaDiscard(Texture2D s_texture,SamplerState s_sampler,float2 texcoord,half scale) {
	FRAGMENT_ALPHA_OUT OUT;
	OUT.color = s_texture.Sample(s_sampler,texcoord);
	#ifdef ALPHA_TEST
		OUT.color.w = OUT.color.w * scale;
		#ifdef MULTISAMPLE_0
			if(OUT.color.w <= 0.5f) discard;
		#elif USE_ALPHA_TEST_LEVEL_10_1
			#ifdef QUALITY_HIGH
				OUT.coverage = 0x00;
				half2 dx = ddx(texcoord);
				half2 dy = ddy(texcoord);
				#define SAMPLE(X,Y,MASK) if(s_texture.Sample(s_sampler,texcoord + dx * (X) + dy * (Y)).w * scale > 0.5f) OUT.coverage |= MASK;
				#ifdef MULTISAMPLE_2
					SAMPLE( 0.25f, 0.25f,0x01)
					SAMPLE(-0.25f,-0.25f,0x02)
				#elif MULTISAMPLE_4
					SAMPLE(-0.125f,-0.375f,0x01)
					SAMPLE( 0.375f,-0.125f,0x02)
					SAMPLE(-0.375f, 0.125f,0x04)
					SAMPLE( 0.125f, 0.375f,0x08)
				#elif MULTISAMPLE_8
					SAMPLE(-0.125f,-0.375f,0x03)
					SAMPLE( 0.375f,-0.125f,0x0c)
					SAMPLE(-0.375f, 0.125f,0x30)
					SAMPLE( 0.125f, 0.375f,0xc0)
				#elif MULTISAMPLE_16
					SAMPLE(-0.125f,-0.375f,0x000f)
					SAMPLE( 0.375f,-0.125f,0x00f0)
					SAMPLE(-0.375f, 0.125f,0x0f00)
					SAMPLE( 0.125f, 0.375f,0xf000)
				#endif
				#undef SAMPLE
			#else
				#ifdef MULTISAMPLE_2
					if(OUT.color.w < 0.49f) OUT.coverage = 0x00;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x01;
					else OUT.coverage = 0x03;
				#elif MULTISAMPLE_4
					if(OUT.color.w < 0.48f) OUT.coverage = 0x00;
					else if(OUT.color.w < 0.49f) OUT.coverage = 0x01;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x06;
					else if(OUT.color.w < 0.51f) OUT.coverage = 0x0e;
					else OUT.coverage = 0x0f;
				#elif MULTISAMPLE_8
					if(OUT.color.w < 0.48f) OUT.coverage = 0x00;
					else if(OUT.color.w < 0.49f) OUT.coverage = 0x11;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x66;
					else if(OUT.color.w < 0.51f) OUT.coverage = 0xee;
					else OUT.coverage = 0xff;
				#elif MULTISAMPLE_16
					if(OUT.color.w < 0.48f) OUT.coverage = 0x0000;
					else if(OUT.color.w < 0.49f) OUT.coverage = 0x1111;
					else if(OUT.color.w < 0.50f) OUT.coverage = 0x6666;
					else if(OUT.color.w < 0.51f) OUT.coverage = 0xeeee;
					else OUT.coverage = 0xffff;
				#endif
			#endif
		#else
			if(OUT.color.w <= 0.5f) discard;
		#endif
	#endif
	return OUT;
}

/* alpha fade texture sampling
 */
void texture2DAlphaFadeDiscard(Texture2D s_texture,SamplerState s_sampler,half2 position,half threshold) {
	#ifdef USE_ALPHA_FADE && ALPHA_FADE
		half4 value = s_texture.Sample(s_sampler,position * (1.0f / 64.0f));
		if(threshold >= 0.0f) {
			if(value.x >= threshold) discard;
		} else {
			if(value.x < 1.0f + threshold) discard;
		}
	#endif
}

/* normal texture sampling
 */
half3 texture2DNormal(Texture2D s_texture,SamplerState s_sampler,float2 texcoord) {
	half3 value = s_texture.Sample(s_sampler,texcoord).xyz;
	value.z = sqrt(saturate(1.0f - dot(value.xy,value.xy)));
	return value;
}

half3 texture2DLevelZeroNormal(Texture2D s_texture,SamplerState s_sampler,float2 texcoord) {
	half3 value = s_texture.SampleLevel(s_sampler,texcoord,0.0f).xyz;
	value.z = sqrt(saturate(1.0f - dot(value.xy,value.xy)));
	return value;
}

/* lightmap texture sampling
 */
half3 texture2DLightMap(Texture2D s_texture,SamplerState s_sampler,float2 texcoord,half3 normal) {
	#ifdef USE_DIRECTIONAL_LIGHTMAPS
		texcoord *= 0.5f;
		#ifdef QUALITY_MEDIUM
			half4 weight;
			weight.x = normal.z;
			weight.y = saturate(dot(half3(0.816496f,0.0f,0.577350f),normal));
			weight.z = saturate(dot(half3(-0.408248f, 0.707106f,0.577350f),normal));
			weight.w = saturate(dot(half3(-0.408248f,-0.707106f,0.577350f),normal));
			weight = weight * weight;
			weight = weight * weight;
			half3 value_0 = s_texture.Sample(s_sampler,texcoord).xyz * weight.x;
			half3 value_1 = s_texture.Sample(s_sampler,texcoord + half2(0.5f,0.0f)).xyz * weight.y;
			half3 value_2 = s_texture.Sample(s_sampler,texcoord + half2(0.0f,0.5f)).xyz * weight.z;
			half3 value_3 = s_texture.Sample(s_sampler,texcoord + half2(0.5f,0.5f)).xyz * weight.w;
			return (value_0 + value_1 + value_2 + value_3) / dot(weight,1.0f);
		#else
			return s_texture.Sample(s_sampler,texcoord).xyz;
		#endif
	#else
		return s_texture.Sample(s_sampler,texcoord).xyz;
	#endif
}

/* cubic texture sampling
 */
half3 texture_2d_cubic_filter(float x) {
	half x1 = frac(x);
	half x2 = x1 * x1;
	half x3 = x2 * x1;
	half x13 = x1 * 3.0f;
	half x23 = x2 * 3.0f;
	half x33 = x3 * 3.0f;
	half w0 = -x3 + x23 - x13 + 1.0f;
	half w1 = x33 - x23 * 2.0f + 4.0f;
	half w2 = -x33 + x23 + x13 + 1.0f;
	return half3(1.0f + x3 / (w2 + x3) - x1,1.0f - w1 / (w0 + w1) + x1,(w2 + x3) * (1.0f / 6.0f));
}

half4 texture2DCubic(Texture2D s_texture,SamplerState s_sampler,float2 texcoord,float4 texsize) {
	#ifdef QUALITY_HIGH
		float2 texcoord_hg = texcoord * texsize.xy - 0.5f;
		half3 hg_x = texture_2d_cubic_filter(texcoord_hg.x);
		half3 hg_y = texture_2d_cubic_filter(texcoord_hg.y);
		float4 texcoords = texcoord.xyxy + half4(-hg_x.y,-hg_y.y,hg_x.x,hg_y.x) * texsize.zwzw;
		half4 value_00 = s_texture.Sample(s_sampler,texcoords.xy);
		half4 value_10 = s_texture.Sample(s_sampler,texcoords.xw);
		half4 value_01 = s_texture.Sample(s_sampler,texcoords.zy);
		half4 value_11 = s_texture.Sample(s_sampler,texcoords.zw);
		return lerp(lerp(value_00,value_10,hg_y.z),lerp(value_01,value_11,hg_y.z),hg_x.z);
	#else
		return s_texture.Sample(s_sampler,texcoord);
	#endif
}

/* linear shadow sampling
 */
float shadow2DArrayLinear(Texture2DArray s_texture,SamplerState s_sampler,float3 texcoord,float4 texsize,float compare) {
	#ifdef QUALITY_MEDIUM
		float offset = 0.5f - 0.01f;
		float2 weights = frac(texcoord.xy * texsize.xy - offset);
		float4 texcoords = float4(-offset,-offset,offset,offset) * texsize.zwzw;
		float value_00 = (compare < s_texture.Sample(s_sampler,texcoord + float3(texcoords.xy,0.0f)).x);
		float value_10 = (compare < s_texture.Sample(s_sampler,texcoord + float3(texcoords.zy,0.0f)).x);
		float value_01 = (compare < s_texture.Sample(s_sampler,texcoord + float3(texcoords.xw,0.0f)).x);
		float value_11 = (compare < s_texture.Sample(s_sampler,texcoord + float3(texcoords.zw,0.0f)).x);
		return lerp(lerp(value_00,value_10,weights.x),lerp(value_01,value_11,weights.x),weights.y);
	#else
		return (compare < s_texture.Sample(s_sampler,texcoord).x);
	#endif
}

/*
 */
#include <deferred_base.h>
#ifdef AMBIENT || PROB || SPOT || OMNI || PROJ || WORLD
	#include <fragment_base_shading.h>
#endif
#ifdef OMNI
	#include <fragment_base_shadow_omni.h>
#elif PROJ
	#include <fragment_base_shadow_proj.h>
#elif AMBIENT_LIGHT || WORLD
	#include <fragment_base_shadow_world.h>
#endif

/******************************************************************************\
*
* Direct3D9
*
\******************************************************************************/

#elif DIRECT3D9

/*
 */
#include <VCommon.h>

/* texture samplers

sampler s_texture_0 : register(s0);
sampler s_texture_1 : register(s1);
sampler s_texture_2 : register(s2);
sampler s_texture_3 : register(s3);
sampler s_texture_4 : register(s4);
sampler s_texture_5 : register(s5);
sampler s_texture_6 : register(s6);
sampler s_texture_7 : register(s7);
sampler s_texture_8 : register(s8);
sampler s_texture_9 : register(s9);
sampler s_texture_10 : register(s10);
sampler s_texture_11 : register(s11);
sampler s_texture_12 : register(s12);
sampler s_texture_13 : register(s13);
sampler s_texture_14 : register(s14);
sampler s_texture_15 : register(s15);
 */
/* vertex transformation
 */
float4 getPosition(float4 vertex) {
	return mul4(s_projection,vertex);
}

/* fragment deferred out
 */
struct FRAGMENT_DEFERRED_OUT {
	half4 color_0 : COLOR0;
	#ifdef HAS_DEFERRED_COLOR
		half4 color_1 : COLOR1;
	#endif
	#ifdef HAS_DEFERRED_NORMAL
		half4 color_2 : COLOR2;
	#endif
	#ifdef USE_PARALLAX
		half4 color_3 : COLOR3;
	#endif
};

/* alpha test texture sampling
 */
half4 tex2DAlpha(sampler2D s_texture,float2 texcoord,half scale) {
	half4 value = tex2D(s_texture,texcoord);
	#ifdef ALPHA_TEST
		value.w = value.w * scale;
		#ifdef MULTISAMPLE_0 || !USE_ALPHA_TO_COVERAGE
			if(value.w <= 0.5f) discard;
		#else
			value.w = value.w * 4.0f - 1.5f;
		#endif
	#endif
	return value;
}

half4 tex2DAlphaDiscard(sampler2D s_texture,float2 texcoord,half scale) {
	half4 value = tex2D(s_texture,texcoord);
	#ifdef ALPHA_TEST
		value.w = value.w * scale;
		if(value.w <= 0.5f) discard;
	#endif
	return value;
}

/* alpha fade texture sampling
 */
void tex2DAlphaFadeDiscard(sampler2D s_texture,float4 texcoord,half threshold) {
	#ifdef USE_ALPHA_FADE && ALPHA_FADE
		texcoord.xy *= 64.0f;
		half4 value = tex2Dproj(s_texture,texcoord);
		if(threshold >= 0.0f) {
			if(value.x >= threshold) discard;
		} else {
			if(value.x < 1.0f + threshold) discard;
		}
	#endif
}

/* normal texture sampling
 */
half3 tex2DNormal(sampler2D s_texture,float2 texcoord) {
	half3 value = tex2D(s_texture,texcoord).xyz;
	value.xy = value.xy * 2.0f - 1.0f;
	value.z = sqrt(saturate(1.0f - dot(value.xy,value.xy)));
	return value;
}

half3 tex2DLodNormal(sampler2D s_texture,float2 texcoord) {
	half3 value = tex2Dlod(s_texture,half4(texcoord,0.0f,0.0f)).xyz;
	value.xy = value.xy * 2.0f - 1.0f;
	value.z = sqrt(saturate(1.0f - dot(value.xy,value.xy)));
	return value;
}

/* lightmap texture sampling
 */
half3 tex2DLightMap(sampler2D s_texture,float2 texcoord,half3 normal) {
	#ifdef USE_DIRECTIONAL_LIGHTMAPS
		texcoord *= 0.5f;
		#ifdef QUALITY_MEDIUM
			half4 weight;
			weight.x = normal.z;
			weight.y = saturate(dot(half3(0.816496f,0.0f,0.577350f),normal));
			weight.z = saturate(dot(half3(-0.408248f, 0.707106f,0.577350f),normal));
			weight.w = saturate(dot(half3(-0.408248f,-0.707106f,0.577350f),normal));
			weight = weight * weight;
			weight = weight * weight;
			half3 value_0 = tex2D(s_texture,texcoord).xyz * weight.x;
			half3 value_1 = tex2D(s_texture,texcoord + half2(0.5f,0.0f)).xyz * weight.y;
			half3 value_2 = tex2D(s_texture,texcoord + half2(0.0f,0.5f)).xyz * weight.z;
			half3 value_3 = tex2D(s_texture,texcoord + half2(0.5f,0.5f)).xyz * weight.w;
			return (value_0 + value_1 + value_2 + value_3) / dot(weight,1.0f);
		#else
			return tex2D(s_texture,texcoord).xyz;
		#endif
	#else
		return tex2D(s_texture,texcoord).xyz;
	#endif
}

/* linear texture sampling
 */
half4 tex2DLinear(sampler2D s_texture,float2 texcoord,float4 texsize) {
	#ifdef ATI_R500
		half offset = 0.5f - 0.01f;
		half2 weights = frac(texcoord * texsize.xy - offset);
		float4 texcoords = texcoord.xyxy + half4(-offset,-offset,offset,offset) * texsize.zwzw;
		half4 value_00 = tex2D(s_texture,texcoords.xy);
		half4 value_10 = tex2D(s_texture,texcoords.zy);
		half4 value_01 = tex2D(s_texture,texcoords.xw);
		half4 value_11 = tex2D(s_texture,texcoords.zw);
		return lerp(lerp(value_00,value_10,weights.x),lerp(value_01,value_11,weights.x),weights.y);
	#else
		return tex2D(s_texture,texcoord);
	#endif
}

/* cubic texture sampling
 */
half3 tex_2d_cubic_filter(float x) {
	half x1 = frac(x);
	half x2 = x1 * x1;
	half x3 = x2 * x1;
	half x13 = x1 * 3.0f;
	half x23 = x2 * 3.0f;
	half x33 = x3 * 3.0f;
	half w0 = -x3 + x23 - x13 + 1.0f;
	half w1 = x33 - x23 * 2.0f + 4.0f;
	half w2 = -x33 + x23 + x13 + 1.0f;
	return half3(1.0f + x3 / (w2 + x3) - x1,1.0f - w1 / (w0 + w1) + x1,(w2 + x3) * (1.0f / 6.0f));
}

half4 tex2DCubic(sampler s_texture,float2 texcoord,float4 texsize) {
	#ifdef QUALITY_HIGH
		float2 texcoord_hg = texcoord * texsize.xy - 0.5f;
		half3 hg_x = tex_2d_cubic_filter(texcoord_hg.x);
		half3 hg_y = tex_2d_cubic_filter(texcoord_hg.y);
		float4 texcoords = texcoord.xyxy + half4(-hg_x.y,-hg_y.y,hg_x.x,hg_y.x) * texsize.zwzw;
		half4 value_00 = tex2DLinear(s_texture,texcoords.xy,texsize);
		half4 value_10 = tex2DLinear(s_texture,texcoords.xw,texsize);
		half4 value_01 = tex2DLinear(s_texture,texcoords.zy,texsize);
		half4 value_11 = tex2DLinear(s_texture,texcoords.zw,texsize);
		return lerp(lerp(value_00,value_10,hg_y.z),lerp(value_01,value_11,hg_y.z),hg_x.z);
	#else
		return tex2DLinear(s_texture,texcoord,texsize);
	#endif
}

/* linear shadow sampling
 */
half shadow2DLinear(sampler s_texture,float2 texcoord,float4 texsize,half compare) {
	#ifdef QUALITY_MEDIUM
		#ifdef USE_ATI_TEXTURE_FETCH4
			half2 weights = frac(texcoord * texsize.xy);
			half4 samples = (compare < tex2D(s_texture,texcoord - weights * texsize.zw));
			return lerp(lerp(samples.w,samples.x,weights.x),lerp(samples.y,samples.z,weights.x),weights.y);
		#else
			half offset = 0.5f - 0.01f;
			half2 weights = frac(texcoord * texsize.xy - offset);
			float4 texcoords = texcoord.xyxy + half4(-offset,-offset,offset,offset) * texsize.zwzw;
			half value_00 = (compare < tex2D(s_texture,texcoords.xy).x);
			half value_10 = (compare < tex2D(s_texture,texcoords.zy).x);
			half value_01 = (compare < tex2D(s_texture,texcoords.xw).x);
			half value_11 = (compare < tex2D(s_texture,texcoords.zw).x);
			return lerp(lerp(value_00,value_10,weights.x),lerp(value_01,value_11,weights.x),weights.y);
		#endif
	#else
		return (compare < tex2D(s_texture,texcoord).x);
	#endif
}

half shadow2DLodLinear(sampler s_texture,float2 texcoord,float4 texsize,half compare) {
	#ifdef QUALITY_MEDIUM
		#ifdef USE_ATI_TEXTURE_FETCH4
			half2 weights = frac(texcoord * texsize.xy);
			half4 samples = (compare < tex2Dlod(s_texture,half4(texcoord - weights * texsize.zw,0.0f,0.0f)));
			return lerp(lerp(samples.w,samples.x,weights.x),lerp(samples.y,samples.z,weights.x),weights.y);
		#else
			half offset = 0.5f - 0.01f;
			half2 weights = frac(texcoord * texsize.xy - offset);
			float4 texcoords = texcoord.xyxy + half4(-offset,-offset,offset,offset) * texsize.zwzw;
			half value_00 = (compare < tex2Dlod(s_texture,half4(texcoords.xy,0.0f,0.0f)).x);
			half value_10 = (compare < tex2Dlod(s_texture,half4(texcoords.zy,0.0f,0.0f)).x);
			half value_01 = (compare < tex2Dlod(s_texture,half4(texcoords.xw,0.0f,0.0f)).x);
			half value_11 = (compare < tex2Dlod(s_texture,half4(texcoords.zw,0.0f,0.0f)).x);
			return lerp(lerp(value_00,value_10,weights.x),lerp(value_01,value_11,weights.x),weights.y);
		#endif
	#else
		return (compare < tex2Dlod(s_texture,half4(texcoord,0.0f,0.0f)).x);
	#endif
}

/*
 */
#include <deferred_base.h>
#ifdef AMBIENT || PROB || SPOT || OMNI || PROJ || WORLD
	#include <fragment_base_shading.h>
#endif
#ifdef OMNI
	#include <fragment_base_shadow_omni.h>
#elif PROJ
	#include <fragment_base_shadow_proj.h>
#elif AMBIENT_LIGHT || WORLD
	#include <fragment_base_shadow_world.h>
#endif

#endif /* __FRAGMENT_BASE_H__ */
